package top.mcwebsite.playandroid.lib.servicemanager.core

import kotlin.jvm.internal.Reflection
import kotlin.reflect.KClass

object ServiceManager {

    private val serviceMap = mutableMapOf<KClass<*>, List<ServiceImplBean<*>>>()

    private val singletonServiceMap = mutableMapOf<KClass<out Any>, Any>()

    fun init() {
        ServiceImplProviderInject.inject()
    }

    fun registerServiceByServiceProvider(serviceProvider: IServiceProvider) {
        println("serviceProvider = $serviceProvider")
        println("Load Services: ")
        serviceProvider.getServiceImplBeans().forEach { (kClass, serviceImplBeans) ->
            serviceImplBeans.forEach {
                println("service = ${it.serviceImplClass}")
            }
            serviceMap[kClass] = if (serviceMap.contains(kClass)) {
                serviceMap[kClass]!! + serviceImplBeans
            } else {
                serviceImplBeans
            }
        }
    }

    fun <T : Any> getService(serviceClass: KClass<T>): T? {
        return serviceMap[serviceClass]?.first()?.let { serviceImplBean ->
            if (!serviceImplBean.isSingleton) {
                serviceImplBean.factory.create()
            } else {
                if (singletonServiceMap.contains(serviceImplBean.serviceImplClass)) {
                    singletonServiceMap[serviceImplBean.serviceImplClass]!!
                } else {
                    serviceImplBean.factory.create().also {
                        singletonServiceMap[serviceImplBean.serviceImplClass] = it
                    }
                }
            } as? T
        }
    }

    fun <T : Any> getService(serviceClass: Class<T>): T? {
        return getService(Reflection.createKotlinClass(serviceClass) as KClass<T>)
    }

    inline fun <reified T : Any> getService(): T {
        return getOrNullService<T>()
            ?: throw IllegalStateException("未查找到 ${T::class.java} 的实现类，请检查 ${T::class.simpleName} 是否添加 @ServiceImpl 注解，以及是否添加依赖")
    }

    inline fun <reified T : Any> getOrNullService(): T? {
        return getService(T::class)
    }


}
